package cn.aitrox.ry.service.image.service.impl;

import cn.aitrox.ry.bean.RespResult;
import cn.aitrox.ry.common.exception.CustomBizException;
import cn.aitrox.ry.common.service.BaseService;
import cn.aitrox.ry.constant.CommonConstant;
import cn.aitrox.ry.enumtype.ProcessStatusEnum;
import cn.aitrox.ry.enumtype.RespCodeEnum;
import cn.aitrox.ry.service.image.bean.ImageTransferHandlerDelegate;
import cn.aitrox.ry.service.image.dao.ImageInfoDao;
import cn.aitrox.ry.service.image.dao.ImageTransferItemDao;
import cn.aitrox.ry.service.image.dto.image.transfer.out.ImageTransferResultExportDataDto;
import cn.aitrox.ry.service.image.dto.image.transfer.out.ImageTransferResultQueryOutDto;
import cn.aitrox.ry.service.image.entity.ImageInfoMongoEntity;
import cn.aitrox.ry.service.image.entity.ImageTransferItemEntity;
import cn.aitrox.ry.service.image.enumtype.ImageGroupTypeEnum;
import cn.aitrox.ry.service.image.mq.msg.ImageTransferMsg;
import cn.aitrox.ry.service.image.mq.produser.ImageTransferProduser;
import cn.aitrox.ry.service.image.service.ImageTransferService;
import cn.aitrox.ry.util.ArrayUtil;
import cn.aitrox.ry.util.LogUtil;
import cn.aitrox.ry.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class ImageTransferServiceImpl extends BaseService implements ImageTransferService {

    private static final Logger LOG = LoggerFactory.getLogger(ImageTransferServiceImpl.class);

    @Autowired
    private ImageTransferItemDao imageTransferItemDao;

    @Autowired
    private ImageTransferProduser imageTransferProduser;

    @Autowired
    private ImageTransferHandlerDelegate imageTransferHandlerDelegate;

    @Autowired
    private ImageInfoDao imageInfoDao;

    @Override
    public RespResult handlerMsg(ImageTransferMsg imageTransferMsg, long startTime) {
        Integer imageTransferItemId = imageTransferMsg.getId();
        ImageTransferItemEntity itemEntity = imageTransferItemDao.findById(imageTransferItemId);
        if (null == itemEntity) {
            throw new CustomBizException("ID不存在");
        }

        ProcessStatusEnum processStatusEnum = ProcessStatusEnum.getEnum(itemEntity.getStatus());

        // 如果是已暂停状态，不进行处理
        if (processStatusEnum == ProcessStatusEnum.PAUSE) {
            LOG.info(LogUtil.gen("ImageTransferServiceImpl handlerMsg PAUSE .....", "id", imageTransferItemId.toString()));
            return RespResult.ok();
        }

        // 校验该转换模式是否已经有数据，已有数据直接处理成功
        List<ImageInfoMongoEntity> imageInfoMongoEntityList = imageInfoDao.query(Arrays.asList(itemEntity.getSeriesUid()), ImageGroupTypeEnum.SERIES_IMAGE_TRANSFER.getGroupType(), Arrays.asList(itemEntity.getMode()));
        if (!ArrayUtil.isEmpty(imageInfoMongoEntityList)) {
            this.handlerSuccess(imageTransferItemId, startTime);
            return RespResult.ok();
        }

        // 校验只有未开始的状态才可以进行处理
        if (processStatusEnum != ProcessStatusEnum.NOT_START) {
            return RespResult.secByError(RespCodeEnum.ERROR.getCode(), "处理流水状态不是未开始");
        }

        // 修改状态为处理中以及尝试次数+1
        ImageTransferItemEntity update = new ImageTransferItemEntity();
        update.setId(imageTransferItemId);
        update.setStatus(ProcessStatusEnum.PROCESSING.getStatus());
        update.setTryCount(itemEntity.getTryCount() + 1);
        update.setErrMsg(CommonConstant.EMPTY);
        update.setRunTime(0L);
        imageTransferItemDao.updateByIdSelective(update);

        // 根据不用的转换模式选择不同的转换策略进行处理
        RespResult respResult = imageTransferHandlerDelegate.handler(itemEntity);

        if (respResult._isOk()) {
            this.handlerSuccess(imageTransferItemId, startTime);
        } else {
            this.handlerFail(imageTransferItemId, respResult.getMsg(), startTime);
        }
        return respResult;
    }

    @Override
    public ImageTransferResultQueryOutDto resultQuery(String transferId, Integer relationType, String mode) {
        List<ImageTransferItemEntity> itemListInDB = imageTransferItemDao.findByCondition(packQueryCond(transferId, relationType, mode), null);
        if (ArrayUtil.isEmpty(itemListInDB)) {
            return new ImageTransferResultQueryOutDto(mode, new ArrayList<>(), 0, 0, 0, 0, 0, 0, 0);
        }
        List<String> seriesList = new ArrayList<>();

        int totalCount = itemListInDB.size();

        int failCount = 0;

        int successCount = 0;

        int processCount = 0;

        int notStartCount = 0;

        int pauseCount = 0;

        for (ImageTransferItemEntity item : itemListInDB) {
            seriesList.add(item.getSeriesUid());
            ProcessStatusEnum statusEnum = ProcessStatusEnum.getEnum(item.getStatus());
            switch (statusEnum) {
                case SUCCESS:
                    successCount++;
                    break;
                case FAIL:
                    failCount++;
                    break;
                case NOT_START:
                    notStartCount++;
                    break;
                case PROCESSING:
                    processCount++;
                    break;
                case PAUSE:
                    pauseCount++;
                    break;
                default:
                    break;
            }
        }
        ProcessStatusEnum processStatusEnum;
        if (failCount > 0) {
            processStatusEnum = ProcessStatusEnum.FAIL;
        } else if (successCount == totalCount) {
            processStatusEnum = ProcessStatusEnum.SUCCESS;
        } else if (pauseCount > 0) {
            processStatusEnum = ProcessStatusEnum.PAUSE;
        } else if (notStartCount > 0 || processCount > 0) {
            processStatusEnum = ProcessStatusEnum.PROCESSING;
        } else {
            processStatusEnum = ProcessStatusEnum.NOT_START;
        }
        return new ImageTransferResultQueryOutDto(mode, seriesList, processStatusEnum.getStatus(), totalCount, failCount, successCount, processCount, notStartCount, pauseCount);
    }

    @Override
    public RespResult execute(String transferId, Integer relationType, String mode, List<String> seriesUids) {
        List<ImageTransferItemEntity> itemListInDB = imageTransferItemDao.findByCondition(packQueryCond(transferId, relationType, mode), null);
        List<String> seriesListInDB = itemListInDB.stream().map(ImageTransferItemEntity::getSeriesUid).collect(Collectors.toList());

        // 需要保存的
        List<ImageTransferItemEntity> itemList2Save = seriesUids.stream().filter(x -> !seriesListInDB.contains(x)).map(x -> {
            return new ImageTransferItemEntity(null, transferId, relationType, x, mode, ProcessStatusEnum.NOT_START.getStatus(), 0, null, 0L);
        }).collect(Collectors.toList());

        // 需要修改状态的
        List<Integer> itemIdList2Update = itemListInDB.stream().filter(x -> !ProcessStatusEnum._isSuccess(x.getStatus()) && seriesUids.contains(x.getSeriesUid())).map(ImageTransferItemEntity::getId).collect(Collectors.toList());

        if (ArrayUtil.isEmpty(itemList2Save) && ArrayUtil.isEmpty(itemIdList2Update)) {
            return RespResult.ok();
        }

        if (!ArrayUtil.isEmpty(itemList2Save)) {
            imageTransferItemDao.batchSave(itemList2Save);

            List<String> seriesList2Save = itemList2Save.stream().map(ImageTransferItemEntity::getSeriesUid).collect(Collectors.toList());

            itemList2Save = imageTransferItemDao.queryBySeries(transferId, relationType, mode, seriesList2Save);

            itemList2Save.stream().forEach(x -> imageTransferProduser.send(x.getId()));
        }

        if (!ArrayUtil.isEmpty(itemIdList2Update)) {
            ImageTransferItemEntity update = new ImageTransferItemEntity(null, null, null, null, null, ProcessStatusEnum.NOT_START.getStatus(), null, CommonConstant.EMPTY, 0L);
            imageTransferItemDao.updateByIdsSelective(update, itemIdList2Update.toArray());
            itemIdList2Update.stream().forEach(x -> imageTransferProduser.send(x));
        }


        return RespResult.ok();
    }

    @Override
    public RespResult restart(String transferId, Integer relationType, String mode) {
        ImageTransferItemEntity cond = packQueryCond(transferId, relationType, mode);
        cond.setStatus(ProcessStatusEnum.FAIL.getStatus());
        List<ImageTransferItemEntity> itemListInDB = imageTransferItemDao.findByCondition(cond, null);
        if (ArrayUtil.isEmpty(itemListInDB)) {
            return RespResult.ok();
        }
        List<Integer> ids = itemListInDB.stream().map(ImageTransferItemEntity::getId).collect(Collectors.toList());
        ImageTransferItemEntity update = new ImageTransferItemEntity(null, null, null, null, null, ProcessStatusEnum.NOT_START.getStatus(), null, CommonConstant.EMPTY, 0L);
        imageTransferItemDao.updateByIdsSelective(update, ids.toArray());
        ids.stream().forEach(x -> imageTransferProduser.send(x));
        return RespResult.ok();
    }


    @Override
    public RespResult pause(String transferId, Integer relationType, String mode) {
        ImageTransferItemEntity cond = packQueryCond(transferId, relationType, mode);
        cond.setStatus(ProcessStatusEnum.NOT_START.getStatus());
        List<ImageTransferItemEntity> itemListInDB = imageTransferItemDao.findByCondition(cond, null);
        if (ArrayUtil.isEmpty(itemListInDB)) {
            return RespResult.ok();
        }
        List<Integer> ids = itemListInDB.stream().map(ImageTransferItemEntity::getId).collect(Collectors.toList());
        ImageTransferItemEntity update = new ImageTransferItemEntity(null, null, null, null, null, ProcessStatusEnum.PAUSE.getStatus(), null, CommonConstant.EMPTY, 0L);
        imageTransferItemDao.updateByIdsSelective(update, ids.toArray());
        ids.stream().forEach(id -> imageTransferProduser.send(id));
        return RespResult.ok();
    }

    @Override
    public List<ImageTransferResultExportDataDto> resultExport(String transferId, Integer relationType, String mode, List<String> seriesUids) {
        List<ImageTransferItemEntity> itemListInDB = imageTransferItemDao.findByCondition(packQueryCond(transferId, relationType, mode), null);
        return itemListInDB.stream().filter(x -> seriesUids.contains(x.getSeriesUid())).map(x -> new ImageTransferResultExportDataDto(x.getId(), x.getSeriesUid(), x.getStatus(), x.getErrMsg())).collect(Collectors.toList());
    }

    @Override
    public void handlerFail(Integer id, String errMsg, long startTime) {
        ImageTransferItemEntity update = new ImageTransferItemEntity();
        update.setId(id);
        update.setStatus(ProcessStatusEnum.FAIL.getStatus());
        update.setErrMsg(StringUtil.subStr(errMsg, 1000));
        update.setRunTime(((System.currentTimeMillis() - startTime) / 1000));
        imageTransferItemDao.updateByIdSelective(update);
    }

    private void handlerSuccess(Integer id, long startTime) {
        ImageTransferItemEntity update = new ImageTransferItemEntity();
        update.setId(id);
        update.setStatus(ProcessStatusEnum.SUCCESS.getStatus());
        update.setErrMsg(CommonConstant.EMPTY);
        update.setRunTime(((System.currentTimeMillis() - startTime) / 1000));
        imageTransferItemDao.updateByIdSelective(update);
    }

    private ImageTransferItemEntity packQueryCond(String transferId, Integer relationType, String mode) {
        return new ImageTransferItemEntity(null, transferId, relationType, null, mode, null, null, null, null);
    }
}
